﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Data;
using System.Linq.Expressions;
using System.Data.Linq;
using System.ComponentModel;
using OneShoppingModel;

namespace OneShoppingDAL
{
    /// <summary>
    /// Linq通用数据访问类
    /// </summary>
    /// <typeparam name="TDataBase"></typeparam>
    public  class LinqUtility
    {

        private static LinqUtility instance;

        public static LinqUtility GetInstance()
        {
            if (instance == null)
            {
                instance = new LinqUtility();
            }
            return instance;
        }

        
        /// <summary>
        /// 获取所有数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public  List<T> GetList<T>(OneShoppingDataContext db) where T : class
        {
            return db.GetTable<T>().ToList();

        }
       


        /// <summary>
        /// 按条件查询，获取某条件下的所有数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="predicate">Lambda表达式</param>
        /// <returns></returns>
        public  List<T> GetList<T>(OneShoppingDataContext db, 
            Expression<Func<T, bool>> predicate) where T : class
        {
            return db.GetTable<T>().Where(predicate).ToList();
        }

        /// <summary>
        /// 查询分页数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="predicate">Lambda表达式，数据筛选条件</param>
        /// <param name="pageSize">每页数据数</param>
        /// <param name="pageIndex">第几页数据</param>
        /// <returns></returns>
        public  List<T> GetList<T>(OneShoppingDataContext db, 
            Expression<Func<T, bool>> predicate, 
            int pageSize, int pageIndex) where T : class
        {
            return db.GetTable<T>().Where(predicate).Skip<T>((pageIndex - 1) * pageSize).Take<T>(pageSize).ToList();
        }


        /// <summary>
        /// 获取单一实体
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public  T GetEntity<T>(OneShoppingDataContext db, 
            Expression<Func<T, bool>> predicate) where T : class
        {
            
            return db.GetTable<T>().Where(predicate).FirstOrDefault();
        }

        /// <summary>
        /// 添加实体
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="entity"></param>
        public  bool InsertEntity<T>(OneShoppingDataContext db, T entity) where T : class
        {
            try
            {
                //将对象保存到上下文当中
                db.GetTable<T>().InsertOnSubmit(entity);
                //提交更改
                db.SubmitChanges();
                return true;
            }
            catch (Exception ex)
            {
                return false;
                throw new Exception(ex.Message);
            }
        }

        /// <summary>
        /// 修改实体
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="entity"></param>
        public  bool UpdateEntity<T>(OneShoppingDataContext db, T entity) where T : class,new()
        {
            try
            {

                //Detach<T>(entity);//若有外键关系需要
                //将新实体附加到上下文cb中
                db.GetTable<T>().Attach(entity);
                //刷新数据库
                db.Refresh(RefreshMode.KeepCurrentValues, entity);
                //提交更改
                db.SubmitChanges(ConflictMode.ContinueOnConflict);
                return true;
            }
            catch (Exception ex)
            {
                return false;
                throw new Exception(ex.Message);
            }
        }

        /// <summary>
        /// 删除实体
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="predicate">删除的Lambda条件表达式</param>
        public  bool DeleteEntity<T>(OneShoppingDataContext db, Expression<Func<T, bool>> predicate) where T : class
        {
            try
            {
                //获取要删除的实体
                var entity = db.GetTable<T>().Where(predicate).FirstOrDefault();
                db.GetTable<T>().DeleteOnSubmit(entity);
                db.SubmitChanges(ConflictMode.ContinueOnConflict);
                return true;
            }
            catch (Exception ex)
            {
                return false;
                throw new Exception(ex.Message);
            }
        }


        //使用反射克隆一个不包含关联的对象
        public  T Clone<T>(T source) where T : new()
        {
            T t = new T();
            var ps = source.GetType().GetProperties().Where(p => p.GetCustomAttributes(false)
               .Where(a => a is System.Data.Linq.Mapping.ColumnAttribute).Count() != 0);
            foreach (var item in ps)
            {
                t.GetType().GetProperty(item.Name).SetValue(t, item.GetValue(source, null), null);
            }
            return t;
        }

        public  void Detach<T>(T entity)
        {
            foreach (FieldInfo fi in entity.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.
        Instance))
            {
                if (fi.FieldType.ToString().Contains("EntityRef"))
                {
                    var value = fi.GetValue(entity);
                    if (value != null)
                    {
                        fi.SetValue(entity, null);
                    }
                }
                if (fi.FieldType.ToString().Contains("EntitySet"))
                {
                    var value = fi.GetValue(entity);
                    if (value != null)
                    {
                        MethodInfo mi = value.GetType().GetMethod("Clear");
                        if (mi != null)
                        {
                            mi.Invoke(value, null);
                        }
                        fi.SetValue(entity, value);
                    }
                }
            }
        }
    }

}
